// [[ OnflowGenerator File UUID: 60e67738994f4199b49845c49a4b90a0  ]]
package com.itdct.onflow.system.monitor.manager

import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.itdct.onflow.core.config.onflow.MonitorConfig
import com.itdct.onflow.core.extend.logDebug
import com.itdct.onflow.core.extend.updateEx
import com.itdct.onflow.core.util.RedisReentrantLock
import com.itdct.onflow.core.util.RedisUtil
import com.itdct.onflow.system.common.base.BaseManager
import com.itdct.onflow.system.monitor.constant.SysMachineInfoConst
import com.itdct.onflow.system.monitor.entity.SysMachineInfoEntity
import com.itdct.onflow.system.monitor.mapper.SysMachineInfoMapper
import org.springframework.stereotype.Component
import java.math.BigDecimal
import java.math.RoundingMode
import java.net.Inet4Address
import java.net.NetworkInterface
import java.util.*

/**
 * @author DCTANT
 * @date 2025-10-11 17:57:26
 * @version 1.0
 * @description 服务器信息中间层
 */
@Component
class SysMachineInfoManager(
    val sysMachineInfoMapper: SysMachineInfoMapper,
    val monitorConfig: MonitorConfig,
    val redisUtil: RedisUtil,
    val redisReentrantLock: RedisReentrantLock
) : BaseManager() {

    fun getMachineInfo(): SysMachineInfoEntity {
        val systemInfo = oshi.SystemInfo()
        val operatingSystem = systemInfo.operatingSystem
        operatingSystem.versionInfo

        val sysMachineInfoEntity = SysMachineInfoEntity()
        sysMachineInfoEntity.machineId = monitorConfig.machineId

        if (monitorConfig.machineIp.isNotEmpty()) {
            sysMachineInfoEntity.ipAddress = monitorConfig.machineIp
        } else {
            sysMachineInfoEntity.ipAddress = getLocalIp()
        }

        if (monitorConfig.machineMac.isNotEmpty()) {
            sysMachineInfoEntity.macAddress = monitorConfig.machineMac
        } else {
            sysMachineInfoEntity.macAddress = getMacAddress()
        }

        sysMachineInfoEntity.lastReportDate = Date()
        sysMachineInfoEntity.onlineState = SysMachineInfoConst.ONLINE
        sysMachineInfoEntity.osName = systemInfo.operatingSystem.toString()

        val hardware = systemInfo.hardware
        val computerSystem = hardware.computerSystem
        sysMachineInfoEntity.serverName = computerSystem.manufacturer + " " + computerSystem.model
        sysMachineInfoEntity.sn = computerSystem.hardwareUUID

        val processor = hardware.processor
        val processorIdentifier = processor.processorIdentifier
        sysMachineInfoEntity.cpuName = processorIdentifier.name
        sysMachineInfoEntity.cpuFrequency = BigDecimal(processorIdentifier.vendorFreq).divide(BigDecimal(1000000000), 2, RoundingMode.HALF_UP).toString() + " GHz"
        sysMachineInfoEntity.physicalProcessorCount = processor.physicalProcessorCount
        sysMachineInfoEntity.logicalProcessorCount = processor.logicalProcessorCount

        val memory = hardware.memory
        val total = memory.total
        sysMachineInfoEntity.physicalMemory = (total / 1024 / 1024).toInt()
        val virtualMemory = memory.virtualMemory
        sysMachineInfoEntity.virtualMemory = (virtualMemory.swapTotal / 1024 / 1024).toInt()

        var diskStoreTotal = 0L
        val diskStores = systemInfo.hardware.diskStores
        for (diskStore in diskStores) {
            diskStoreTotal += diskStore.size
        }
        sysMachineInfoEntity.totalStorage = BigDecimal(diskStoreTotal / 1024 / 1024).divide(BigDecimal(1024), 2, RoundingMode.HALF_UP)
        return sysMachineInfoEntity
    }

    private fun getLocalIp(): String {
        val interfaces = NetworkInterface.getNetworkInterfaces()
        while (interfaces.hasMoreElements()) {
            val networkInterface = interfaces.nextElement()
            val addresses = networkInterface.inetAddresses
            while (addresses.hasMoreElements()) {
                val address = addresses.nextElement()
                // 核心筛选条件：非回环、IPv4地址、站点本地地址（如192.168.x.x, 10.x.x.x）
                if (!address.isLoopbackAddress && address is Inet4Address && address.isSiteLocalAddress) {
                    networkInterface.hardwareAddress
                    return address.hostAddress
                }
            }
        }
        return ""
    }

    private fun getMacAddress(): String {
        // 获取机器上所有的网络接口
        val networkInterfaces = NetworkInterface.getNetworkInterfaces()
        while (networkInterfaces.hasMoreElements()) {
            val nif = networkInterfaces.nextElement()

            // 筛选条件：接口已启用、不是回环接口、有硬件地址且不是虚拟接口
            if (nif.isUp && !nif.isLoopback && nif.hardwareAddress != null) {
                // 一个额外的可选检查，排除常见的虚拟接口名称
                if (!nif.displayName.lowercase().contains("virtual") &&
                    !nif.name.lowercase().contains("virbr")
                ) {
                    val macBytes = nif.hardwareAddress
                    return macBytes.joinToString(":") { "%02X".format(it) }
                }
            }
        }
        return ""
    }

    fun checkMachineOnline(timeKey: String) {
        if (!monitorConfig.enable) {
            logDebug("服务器监控功能未启用")
            return
        }

        val tryLock = redisReentrantLock.tryLock(timeKey, 15, 10)
        if (!tryLock) {
            return
        }

        val ktQueryWrapper = KtQueryWrapper(SysMachineInfoEntity::class.java)
        ktQueryWrapper.eq(SysMachineInfoEntity::onlineState, SysMachineInfoConst.ONLINE)
        val sysMachineInfoEntities = sysMachineInfoMapper.selectList(ktQueryWrapper)
        for (sysMachineInfoEntity in sysMachineInfoEntities) {
            val lastReportDate = sysMachineInfoEntity.lastReportDate
            if (lastReportDate == null) {
                continue
            }

            if (lastReportDate.time + 60000 < System.currentTimeMillis()) {
                sysMachineInfoEntity.onlineState = SysMachineInfoConst.OFFLINE
                sysMachineInfoMapper.updateEx(sysMachineInfoEntity)
            }
        }
        redisReentrantLock.unlock(timeKey)
    }

}